﻿using System;
using System.IO.Ports;
using System.Windows.Forms;
using System.Threading;
using AutoUpdate.Log;
using ScannerApp.Models;
//BU43
namespace ScannerApp.Common
{
    /// <summary>
    /// Modbos串口通訊
    /// </summary>
    public class Modbus
    {
        private static Mutex m_Mutex = new Mutex();
        private static string strCOMPort;
        private static int intBaud;
        private static int intDataBits;
        private static int intStopBits;
        private static int intParity;
        
        #region 屬性

        public static string COMPort
        {
            get { return strCOMPort; }
            set { strCOMPort = value; }
        }

        public static int Baud
        {
            get { return intBaud; }
            set { intBaud = value; }
        }

        public static int DataBits
        {
            get { return intDataBits; }
            set { intDataBits = value; }
        }

        public static int StopBits
        {
            get { return intStopBits; }
            set { intStopBits = value; }
        }

        public static int Parity
        {
            get { return intParity; }
            set { intParity = value; }
        }

        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <param name="write"></param>
        public static string Read(string write)
        {
            //判斷是否有其他function在讀寫PLC
            if (m_Mutex.WaitOne())
            {
                using (SerialPort m_sp = new SerialPort())
                {
                    string m_strReadBuffer = "";
                    string m_strSendWord = write;
                    string m_strHexTotal = CheckSum(m_strSendWord);
                    string m_strWriteBuffer = string.Concat(":", m_strSendWord, m_strHexTotal, "\r");

                    switch (intParity)
                    {
                        case 0:
                            m_sp.Parity = System.IO.Ports.Parity.None;
                            break;
                        case 1:
                            m_sp.Parity = System.IO.Ports.Parity.Odd;
                            break;
                        case 2:
                            m_sp.Parity = System.IO.Ports.Parity.Even;
                            break;
                    }

                    switch (intStopBits)
                    {
                        case 0:
                            m_sp.StopBits = System.IO.Ports.StopBits.None;
                            break;
                        case 1:
                            m_sp.StopBits = System.IO.Ports.StopBits.One;
                            break;
                        case 2:
                            m_sp.StopBits = System.IO.Ports.StopBits.OnePointFive;
                            break;
                        case 3:
                            m_sp.StopBits = System.IO.Ports.StopBits.Two;
                            break;
                    }

                    m_sp.PortName = strCOMPort;
                    m_sp.BaudRate = intBaud;
                    m_sp.DataBits = intDataBits;
                    m_sp.ReadTimeout = 3000;
                    m_sp.WriteTimeout = 5000;

                    try
                    {
                        m_sp.Open();
                        m_sp.WriteLine(m_strWriteBuffer);

                        try
                        {
                            m_strReadBuffer = m_sp.ReadLine();
                        }
                        catch (InvalidOperationException ex)
                        {
                            m_strReadBuffer = ex.Message;
                        }

                        m_sp.Close();
                    }
                    catch (InvalidOperationException ex)
                    {
                        Logger.Instance.WriteLog(publicclass.UserName + "[ModBus]" + ex.Message, LogType.Error, "ModBus");

                        return "Port Already in use by another application";
                    }
                    catch (System.IO.IOException ex)
                    {
                        Logger.Instance.WriteLog(publicclass.UserName + "[ModBus]" + ex.Message, LogType.Error, "ModBus");

                        return "Port is not Exist";
                    }
                    finally
                    {
                        m_Mutex.ReleaseMutex();
                    }
                    return m_strReadBuffer;
                }
            }
            

            return "";
        }

        private string ToHex(int value)
        {
            int a, b;
            string m_strHexByte = "", m_strHexTotal = "";
            double i;

            for (i = 0; value > 0; i++)
            {
                b = Convert.ToInt32(System.Math.Pow(16.0, i));
                a = value % 16;
                value /= 16;
                
                if (a <= 9)
                {
                    m_strHexByte = a.ToString();
                }
                else
                {
                    switch (a)
                    {
                        case 10:
                            m_strHexByte = "A";
                            break;
                        case 11:
                            m_strHexByte = "B";
                            break;
                        case 12:
                            m_strHexByte = "C";
                            break;
                        case 13:
                            m_strHexByte = "D";
                            break;
                        case 14:
                            m_strHexByte = "E";
                            break;
                        case 15:
                            m_strHexByte = "F";
                            break;
                    }
                }

                m_strHexTotal = String.Concat(m_strHexByte, m_strHexTotal);
            }

            for (; i < 4.0; i++)
            {
                m_strHexTotal = String.Concat("0", m_strHexTotal);
            }

            return m_strHexTotal;
        }

        public static string CheckSum(string writeUncheck)
        {
            char[] m_HexArray = new char[writeUncheck.Length];
            m_HexArray = writeUncheck.ToCharArray();
            int m_DecNum = 0, m_DecNumMSB = 0, m_DecNumLSB = 0;
            int m_DecByte, m_DecByteTotal = 0;

            bool m_bMsb = true;

            for (int i = 0; i <= m_HexArray.GetUpperBound(0); i++)
            {
                if ((m_HexArray[i] >= 48) && (m_HexArray[i] <= 57))
                {
                    m_DecNum = (m_HexArray[i] - 48);
                }
                else if ((m_HexArray[i] >= 65) & (m_HexArray[i] <= 70))
                {
                    m_DecNum = 10 + (m_HexArray[i] - 65);
                }

                if (m_bMsb)
                {
                    m_DecNumMSB = m_DecNum * 16;
                    m_bMsb = false;
                }
                else
                {
                    m_DecNumLSB = m_DecNum;
                    m_bMsb = true;
                }

                if (m_bMsb)
                {
                    m_DecByte = m_DecNumMSB + m_DecNumLSB;
                    m_DecByteTotal += m_DecByte;
                }
            }

            m_DecByteTotal = (255 - m_DecByteTotal) + 1;
            m_DecByteTotal = m_DecByteTotal & 255;

            int a, b = 0;

            string m_strHexByte = "", m_strHexTotal = "";
            double t;

            for (t = 0; m_DecByteTotal > 0; t++)
            {
                b = Convert.ToInt32(System.Math.Pow(16.0, t));
                a = m_DecByteTotal % 16;
                m_DecByteTotal /= 16;

                if (a <= 9)
                {
                    m_strHexByte = a.ToString();
                }
                else
                {
                    switch (a)
                    {
                        case 10:
                            m_strHexByte = "A";
                            break;
                        case 11:
                            m_strHexByte = "B";
                            break;
                        case 12:
                            m_strHexByte = "C";
                            break;
                        case 13:
                            m_strHexByte = "D";
                            break;
                        case 14:
                            m_strHexByte = "E";
                            break;
                        case 15:
                            m_strHexByte = "F";
                            break;
                    }
                }

                m_strHexTotal = String.Concat(m_strHexByte, m_strHexTotal);
            }

            return m_strHexTotal;
        }

        public static double ToDec(string ch, int start, int numOfBytes)
        {
            char[] m_chrHexArray = new char[ch.Length];
            m_chrHexArray = ch.ToCharArray();

            double m_dbDecTotal = 0;
            int x = numOfBytes - 1;
            int m_intUpper = m_chrHexArray.GetUpperBound(0);

            if (m_intUpper >= start + x)
            {
                for (int i = 0; i < numOfBytes; i++)
                {
                    int j = start + i;

                    if ((ch[j] >= 48) && (ch[j] <= 57))
                    {
                        m_dbDecTotal += (ch[j] - 48) * System.Math.Pow(16.0, Convert.ToDouble(x));
                    }
                    else if ((ch[j] >= 65) && (ch[j] <= 70))
                    {
                        m_dbDecTotal += (ch[j] - 55) * System.Math.Pow(16.0, Convert.ToDouble(x));
                    }
                    x--;
                }
            }

            return m_dbDecTotal;
        }

    }
}
